package com.hunan.api.catv.utils;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @Description: MD5签名类
 * @Company: mgtv
 * @author: ningzuojun@mgtv.com
 * @date: 2017年3月9日 上午9:28:32
 */
public class SignMd5Utils {
    private static final Logger logger = Logger.getLogger(SignMd5Utils.class);
    // 签名key
    public static String secret_key;

    /**
     * 签名
     *
     * @param data
     * @return
     */
    public final static boolean signData(TreeMap<String, String> data, String signType) {
        // 获取签名
        String sign = data.get("sign");
        List<String> params = new ArrayList<>();
        // 重组参数
        for (String key : data.keySet()) {
            if (!"sign".equals(key) && !"c222k".equals(key) && !"_".equals(key) && !"callback".equals(key)) {//拿客户的请求进行签名，不需要组装客户的传过来的sign签名字段
                String value = String.format("%s=%s", key, data.get(key));
                params.add(value);
            }
        }
        // 组合参数和签名 secret_key
        String temp = StringUtils.join(params, "&").toLowerCase() + "&secret_key=" + System.getProperty("secret_key");
        logger.info("拼接的签名字符串:" + temp);
        // 签名
        String my_sign = "";
        if (StringUtils.isNotBlank(signType) && "md5".equals(signType)) {
            my_sign = MD5(temp).toLowerCase();
        } else {
            my_sign = sha1(temp).toLowerCase();
        }
        // 返回是否校验成功
        if (!sign.equals(my_sign)) {
            logger.error("签名失败!外部传入的签名为:" + sign + ",本系统的签名为:" + my_sign);
            return false;
        }
        return true;
    }

    public static String getSignStr(TreeMap<String, String> data) {
        // 获取签名
        String sign = data.get("sign");
        List<String> params = new ArrayList<>();
        // 重组参数
        for (String key : data.keySet()) {
            if (!"sign".equals(key) && !"c222k".equals(key) && !"_".equals(key) && !"callback".equals(key)) {//拿客户的请求进行签名，不需要组装客户的传过来的sign签名字段
                String value = String.format("%s=%s", key, data.get(key));
                params.add(value);
            }
        }
        // 组合参数和签名 secret_key
        String temp = (StringUtils.join(params, "&").toLowerCase() + "&secret_key=" + System.getProperty("boss_secret_key")).toLowerCase();
        logger.info("拼接的签名字符串:" + temp);
        return temp;
    }

    /**
     * SHA1签名
     *
     * @param data
     * @return
     */
    public static String sha1(String data) {
        MessageDigest md = null;
        StringBuffer buf = new StringBuffer();
        try {
            md = MessageDigest.getInstance("SHA1");
            md.update(data.getBytes());
            byte[] bits = md.digest();
            for (int i = 0; i < bits.length; i++) {
                int a = bits[i];
                if (a < 0) {

                    a += 256;
                }
                if (a < 16) {

                    buf.append("0");
                }
                buf.append(Integer.toHexString(a));
            }
        } catch (NoSuchAlgorithmException e) {
            logger.error("MD5签名异常:", e);
        }
        return buf.toString();
    }

    /**
     * 获取签名
     *
     * @param signMap
     * @return
     */
    public static String getSign(Map<String, String> signMap, String key) {
        List<String> params = new ArrayList<>();
        // 重组参数
        for (String k : signMap.keySet()) {
            if (!"sign".equals(k)) {//拿客户的请求进行签名，不需要组装客户的传过来的sign签名字段
                String value = String.format("%s=%s", k, signMap.get(k));
                params.add(value);
            }
        }
        // 组合参数和签名 secret_key
        String temp = StringUtils.join(params, "&") + "&key=" + key;
        //md5 temp然后转换大写
        return MD5(temp).toUpperCase();
    }

    /**
     * MD5加密
     *
     * @param s
     * @return
     */
    public static String MD5(String s) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(s.getBytes("utf-8"));
            return toHex(bytes);
        } catch (Exception e) {
            logger.error("MD5签名异常:", e);
        }
        return "";
    }

    /**
     * php和java签名校验
     */
    public static String toMd5(String md5val) throws NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        md5.update(md5val.getBytes());
        /** 获取加密后的字节数组 */
        byte[] md5Bytes = md5.digest();
        String res = "";
        for (int i = 0; i < md5Bytes.length; i++) {
            int temp = md5Bytes[i] & 0xFF;
            if (temp <= 0XF) { // 转化成十六进制不够两位，前面加零
                res += "0";
            }
            res += Integer.toHexString(temp);
        }
        return res;
    }


    private static String toHex(byte[] bytes) {
        final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
        StringBuilder ret = new StringBuilder(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
            ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
        }
        return ret.toString();
    }

    public static String getSignStrByKey(JSONObject data, String keyName, String valueStr) {
        List<String> params = new ArrayList<>();
        // 重组参数
        Iterator iter = data.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry entry = (Map.Entry) iter.next();
            String key = entry.getKey().toString();
            if (!"sign".equals(key) && !"c222k".equals(key) && !"_".equals(key) && !"callback".equals(key)) {//拿客户的请求进行签名，不需要组装客户的传过来的sign签名字段
                String value = String.format("%s=%s", key, entry.getValue().toString());
                params.add(value);
            }
        }
        // 组合参数和签名 secret_key
        String paramStr = (StringUtils.join(params, "&") + "&" + keyName + "=" + valueStr).toLowerCase();
        logger.info("拼接的签名字符串:" + paramStr);
        String sign = sha1(paramStr);
        return sign;
    }
}
